﻿using MongoDB.Bson;
using MongoDB.Driver;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Sustainalytics.ESG.Entities;


namespace Sustainalytics.DataLayer.EsgRatings
{
    public class ControversyIndicatorsRepository : RepositoryCollection<RPControversyIndicator>, IControversyIndicatorsRepository
    {
        public ControversyIndicatorsRepository(string mongoDbUrl)
            : base(mongoDbUrl, null)
        {
        }

        public IList<RPControversyIndicator> ReadAllWhere(
            Guid companyId, 
            Guid? themeId, 
            string clusterName = null, 
            int? skip = null, 
            int? take = null, 
            Ordering<RPControversyIndicator> ordering = null, 
            params Expression<Func<RPControversyIndicator, object>>[] includeFields)
        {
            var query = GetFilterByCompanyId(companyId);
            query = Builders<RPControversyIndicator>.Filter.And(GetFilterByTheme(themeId), query);
            if (!string.IsNullOrEmpty(clusterName))
                query = Builders<RPControversyIndicator>.Filter.And(GetFilterByClusterName(clusterName), query);

            var cursor = Collection().Find(query);

            if (!includeFields.IsNullOrEmpty())
            {
                cursor.Project(Builders<RPControversyIndicator>.Projection.Include(includeFields.Select(x => x.GetPropertyName()).ToArray()));
            }

            if (skip.HasValue)
                cursor = cursor.Skip(skip.Value);
            if (take.HasValue)
                cursor = cursor.Limit(take.Value);
            if (ordering != null)
                cursor = cursor.Sort(ordering.ToMongoSortBy());

            return cursor.ToList();
        }

        private static FilterDefinition<RPControversyIndicator> GetFilterByClusterName(string clusterName)
        {
            if (!string.IsNullOrWhiteSpace(clusterName))
            {
                return Builders<RPControversyIndicator>.Filter.Eq(x => x.Template.IndicatorCategory, clusterName);
            }

            return FilterDefinition<RPControversyIndicator>.Empty;
        }

        private static FilterDefinition<RPControversyIndicator> GetFilterByTheme(Guid? themeId)
        {
            if (themeId.HasValue)
            {
                return Builders<RPControversyIndicator>.Filter.Eq(x => x.Template.ThemeId, themeId.Value);
            }

            return FilterDefinition<RPControversyIndicator>.Empty;
        }

        private static FilterDefinition<RPControversyIndicator> GetFilterByCompanyId(Guid companyId)
        {
            return Builders<RPControversyIndicator>.Filter.Eq(x => x.CompanyId, companyId);
        }
    }
}
